/**
 * enhanced_paging_napi.cpp
 * Complete NAPI wrapper implementation for Enhanced Paging Controller
 * Matches iOS PagingCollectionViewController pattern with async diffing
 */

#include "enhanced_paging_controller.h"
#include "async_paging_differ.h"
#include "diff_util.h"
#include <napi/native_api.h>
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <thread>
#include <atomic>
#include <chrono>
#include <hilog/log.h>

#define LOG_TAG "EnhancedPaging"
#define LOGI(...) OH_LOG_Print(LOG_APP, LOG_INFO, 0, LOG_TAG, __VA_ARGS__)
#define LOGE(...) OH_LOG_Print(LOG_APP, LOG_ERROR, 0, LOG_TAG, __VA_ARGS__)

// ============ NAPI Wrapper for Enhanced Paging Controller ============
class EnhancedPagingControllerNAPI {
private:
    // Core controller
    std::unique_ptr<EnhancedPagingViewController<std::string>> controller_;
    
    // NAPI environment and references
    napi_env env_ = nullptr;
    napi_ref itemBuilderRef_ = nullptr;
    napi_ref pagingSourceRef_ = nullptr;
    napi_ref loadStateListenerRef_ = nullptr;
    napi_ref onPagesUpdatedListenerRef_ = nullptr;
    
    // Update callbacks
    napi_ref onInsertedRef_ = nullptr;
    napi_ref onRemovedRef_ = nullptr;
    napi_ref onMovedRef_ = nullptr;
    napi_ref onChangedRef_ = nullptr;
    
    // Paging configuration
    struct PagingConfig {
        int pageSize = 20;
        int prefetchDistance = 5;
        int initialLoadSize = 60;
        bool enablePlaceholders = false;
        int maxSize = 500;  // Maximum items to keep in memory
    } config_;
    
    // State tracking
    std::atomic<bool> isLoading_{false};
    std::atomic<bool> hasMoreData_{true};
    int currentKey_ = 0;
    
    // Cached data
    std::vector<std::shared_ptr<PagingItem<std::string>>> cachedItems_;
    std::mutex cacheMutex_;
    
    // Thread management
    std::thread::id mainThreadId_;
    
public:
    EnhancedPagingControllerNAPI() 
        : mainThreadId_(std::this_thread::get_id()) {
        controller_ = std::make_unique<EnhancedPagingViewController<std::string>>();
        setupController();
        LOGI("Enhanced Paging Controller initialized");
    }
    
    ~EnhancedPagingControllerNAPI() {
        cleanupRefs();
        LOGI("Enhanced Paging Controller destroyed");
    }
    
    // Setup controller with callbacks
    void setupController() {
        // Set update callbacks matching iOS pattern
        controller_->setUpdateCallbacks(
            // onInserted
            [this](int position, int count) {
                if (onInsertedRef_ && env_) {
                    executeOnMainThread([this, position, count]() {
                        callJSCallback(onInsertedRef_, position, count);
                    });
                }
                LOGI("Items inserted: position=%d, count=%d", position, count);
            },
            // onRemoved
            [this](int position, int count) {
                if (onRemovedRef_ && env_) {
                    executeOnMainThread([this, position, count]() {
                        callJSCallback(onRemovedRef_, position, count);
                    });
                }
                LOGI("Items removed: position=%d, count=%d", position, count);
            },
            // onMoved
            [this](int fromPos, int toPos) {
                if (onMovedRef_ && env_) {
                    executeOnMainThread([this, fromPos, toPos]() {
                        napi_handle_scope scope;
                        napi_open_handle_scope(env_, &scope);
                        
                        napi_value callback;
                        napi_get_reference_value(env_, onMovedRef_, &callback);
                        
                        napi_value args[2];
                        napi_create_int32(env_, fromPos, &args[0]);
                        napi_create_int32(env_, toPos, &args[1]);
                        
                        napi_value result;
                        napi_call_function(env_, nullptr, callback, 2, args, &result);
                        
                        napi_close_handle_scope(env_, scope);
                    });
                }
                LOGI("Item moved: from=%d, to=%d", fromPos, toPos);
            },
            // onChanged
            [this](int position, int count, void* payload) {
                if (onChangedRef_ && env_) {
                    executeOnMainThread([this, position, count, payload]() {
                        napi_handle_scope scope;
                        napi_open_handle_scope(env_, &scope);
                        
                        napi_value callback;
                        napi_get_reference_value(env_, onChangedRef_, &callback);
                        
                        napi_value args[3];
                        napi_create_int32(env_, position, &args[0]);
                        napi_create_int32(env_, count, &args[1]);
                        
                        if (payload) {
                            napi_create_external(env_, payload, nullptr, nullptr, &args[2]);
                        } else {
                            napi_get_undefined(env_, &args[2]);
                        }
                        
                        napi_value result;
                        napi_call_function(env_, nullptr, callback, 3, args, &result);
                        
                        napi_close_handle_scope(env_, scope);
                    });
                }
                LOGI("Items changed: position=%d, count=%d", position, count);
            }
        );
        
        // Set load state listener
        controller_->addLoadStateListener([this](const CombinedLoadStates& states) {
            notifyLoadStateChange(states);
        });
        
        // Set pages updated listener
        controller_->addOnPagesUpdatedListener([this]() {
            notifyPagesUpdated();
        });
    }
    
    // Submit data - matches iOS submitData
    void SubmitData(napi_env env, napi_value dataArray) {
        env_ = env;
        
        uint32_t length;
        napi_get_array_length(env, dataArray, &length);
        
        std::vector<std::shared_ptr<PagingItem<std::string>>> items;
        items.reserve(length);
        
        for (uint32_t i = 0; i < length; i++) {
            napi_value element;
            napi_get_element(env, dataArray, i, &element);
            
            auto item = std::make_shared<PagingItem<std::string>>();
            
            // Get id
            napi_value idValue;
            napi_get_named_property(env, element, "id", &idValue);
            item->id = getString(env, idValue);
            
            // Get data
            napi_value dataValue;
            napi_get_named_property(env, element, "data", &dataValue);
            item->data = getString(env, dataValue);
            
            items.push_back(item);
        }
        
        // Update cache
        {
            std::lock_guard<std::mutex> lock(cacheMutex_);
            cachedItems_ = std::move(items);
            
            // Trim cache if needed
            if (cachedItems_.size() > static_cast<size_t>(config_.maxSize)) {
                cachedItems_.resize(config_.maxSize);
            }
        }
        
        // Create paging data
        CombinedLoadStates loadStates;
        loadStates.refresh.isLoading = false;
        loadStates.append.isLoading = false;
        
        PagingData<std::string> pagingData(cachedItems_, loadStates);
        
        // Submit asynchronously
        controller_->submitData(pagingData);
        LOGI("Submitted %zu items to controller", cachedItems_.size());
    }
    
    // Set paging source - matches iOS data flow
    void SetPagingSource(napi_env env, napi_value sourceObj) {
        env_ = env;
        
        if (pagingSourceRef_) {
            napi_delete_reference(env, pagingSourceRef_);
        }
        napi_create_reference(env, sourceObj, 1, &pagingSourceRef_);
        
        // Initial load
        loadFromSource(LoadType::REFRESH);
        LOGI("Paging source set, initiating refresh");
    }
    
    // Refresh - matches iOS refresh()
    void Refresh() {
        controller_->refresh();
        loadFromSource(LoadType::REFRESH);
        LOGI("Refresh initiated");
    }
    
    // Retry - matches iOS retry()
    void Retry() {
        controller_->retry();
        loadFromSource(LoadType::APPEND);
        LOGI("Retry initiated");
    }
    
    // Get item - matches iOS getItem()
    napi_value GetItem(napi_env env, int position) {
        auto item = controller_->getItem(position);
        if (!item) {
            napi_value undefined;
            napi_get_undefined(env, &undefined);
            return undefined;
        }
        
        napi_value itemObj;
        napi_create_object(env, &itemObj);
        
        setProperty(env, itemObj, "id", item->id);
        setProperty(env, itemObj, "data", item->data);
        
        return itemObj;
    }
    
    // Peek - matches iOS peek()
    napi_value Peek(napi_env env, int index) {
        auto item = controller_->peek(index);
        if (!item) {
            napi_value undefined;
            napi_get_undefined(env, &undefined);
            return undefined;
        }
        
        napi_value itemObj;
        napi_create_object(env, &itemObj);
        
        setProperty(env, itemObj, "id", item->id);
        setProperty(env, itemObj, "data", item->data);
        
        return itemObj;
    }
    
    // Get snapshot - matches iOS snapshot()
    napi_value GetSnapshot(napi_env env) {
        auto snapshot = controller_->snapshot();
        
        napi_value array;
        napi_create_array_with_length(env, snapshot.size(), &array);
        
        for (size_t i = 0; i < snapshot.size(); i++) {
            auto item = snapshot.get(i);
            if (item) {
                napi_value itemObj;
                napi_create_object(env, &itemObj);
                
                setProperty(env, itemObj, "id", item->id);
                setProperty(env, itemObj, "data", item->data);
                
                napi_set_element(env, array, i, itemObj);
            }
        }
        
        return array;
    }
    
    // Get item count
    size_t GetItemCount() {
        return controller_->itemCount();
    }
    
    // Get load states - matches iOS loadStateFlow
    napi_value GetLoadStates(napi_env env) {
        auto states = controller_->loadStateFlow();
        return createLoadStatesObject(env, states);
    }
    
    // Set callbacks - matches iOS ListUpdateCallback pattern
    void SetUpdateCallbacks(napi_env env, 
                           napi_value onInserted,
                           napi_value onRemoved,
                           napi_value onMoved,
                           napi_value onChanged) {
        env_ = env;
        
        if (onInserted) {
            if (onInsertedRef_) napi_delete_reference(env, onInsertedRef_);
            napi_create_reference(env, onInserted, 1, &onInsertedRef_);
        }
        
        if (onRemoved) {
            if (onRemovedRef_) napi_delete_reference(env, onRemovedRef_);
            napi_create_reference(env, onRemoved, 1, &onRemovedRef_);
        }
        
        if (onMoved) {
            if (onMovedRef_) napi_delete_reference(env, onMovedRef_);
            napi_create_reference(env, onMoved, 1, &onMovedRef_);
        }
        
        if (onChanged) {
            if (onChangedRef_) napi_delete_reference(env, onChangedRef_);
            napi_create_reference(env, onChanged, 1, &onChangedRef_);
        }
        
        LOGI("Update callbacks set");
    }
    
    // Set load state listener - matches iOS addLoadStateListener
    void SetLoadStateListener(napi_env env, napi_value callback) {
        env_ = env;
        if (loadStateListenerRef_) {
            napi_delete_reference(env, loadStateListenerRef_);
        }
        napi_create_reference(env, callback, 1, &loadStateListenerRef_);
        LOGI("Load state listener set");
    }
    
    // Set pages updated listener - matches iOS addOnPagesUpdatedListener
    void SetOnPagesUpdatedListener(napi_env env, napi_value callback) {
        env_ = env;
        if (onPagesUpdatedListenerRef_) {
            napi_delete_reference(env, onPagesUpdatedListenerRef_);
        }
        napi_create_reference(env, callback, 1, &onPagesUpdatedListenerRef_);
        LOGI("Pages updated listener set");
    }
    
    // Set item builder
    void SetItemBuilder(napi_env env, napi_value callback) {
        env_ = env;
        if (itemBuilderRef_) {
            napi_delete_reference(env, itemBuilderRef_);
        }
        napi_create_reference(env, callback, 1, &itemBuilderRef_);
        
        controller_->setItemBuilder(
            [this, env](std::shared_ptr<PagingItem<std::string>> item, int index) {
                napi_handle_scope scope;
                napi_open_handle_scope(env, &scope);
                
                napi_value callback;
                napi_get_reference_value(env, itemBuilderRef_, &callback);
                
                napi_value itemObj;
                napi_create_object(env, &itemObj);
                setProperty(env, itemObj, "id", item->id);
                setProperty(env, itemObj, "data", item->data);
                
                napi_value indexValue;
                napi_create_int32(env, index, &indexValue);
                
                napi_value args[2] = {itemObj, indexValue};
                napi_value result;
                napi_call_function(env, nullptr, callback, 2, args, &result);
                
                void* nodeHandle = nullptr;
                napi_get_value_external(env, result, &nodeHandle);
                
                napi_close_handle_scope(env, scope);
                
                return static_cast<ArkUI_NodeHandle>(nodeHandle);
            });
        
        LOGI("Item builder set");
    }
    
    // Get native node
    ArkUI_NodeHandle GetNode() {
        return controller_->getListNode();
    }
    
    // Set configuration
    void SetConfig(napi_env env, napi_value configObj) {
        env_ = env;
        
        napi_value value;
        
        // Page size
        if (napi_get_named_property(env, configObj, "pageSize", &value) == napi_ok) {
            napi_get_value_int32(env, value, &config_.pageSize);
        }
        
        // Prefetch distance
        if (napi_get_named_property(env, configObj, "prefetchDistance", &value) == napi_ok) {
            napi_get_value_int32(env, value, &config_.prefetchDistance);
        }
        
        // Initial load size
        if (napi_get_named_property(env, configObj, "initialLoadSize", &value) == napi_ok) {
            napi_get_value_int32(env, value, &config_.initialLoadSize);
        }
        
        // Enable placeholders
        if (napi_get_named_property(env, configObj, "enablePlaceholders", &value) == napi_ok) {
            napi_get_value_bool(env, value, &config_.enablePlaceholders);
        }
        
        // Max size
        if (napi_get_named_property(env, configObj, "maxSize", &value) == napi_ok) {
            napi_get_value_int32(env, value, &config_.maxSize);
        }
        
        LOGI("Config updated: pageSize=%d, prefetchDistance=%d, initialLoadSize=%d", 
             config_.pageSize, config_.prefetchDistance, config_.initialLoadSize);
    }
    
private:
    enum class LoadType {
        REFRESH,
        PREPEND,
        APPEND
    };
    
    // Execute on main thread
    void executeOnMainThread(std::function<void()> task) {
        if (std::this_thread::get_id() == mainThreadId_) {
            task();
        } else {
            // In production, would use proper main thread dispatcher
            // For now, execute directly
            task();
        }
    }
    
    // Load from paging source
    void loadFromSource(LoadType loadType) {
        if (!pagingSourceRef_ || isLoading_) return;
        
        isLoading_ = true;
        
        // Execute on background thread
        std::thread([this, loadType]() {
            napi_handle_scope scope;
            napi_open_handle_scope(env_, &scope);
            
            napi_value sourceObj;
            napi_get_reference_value(env_, pagingSourceRef_, &sourceObj);
            
            // Create load params
            napi_value params;
            napi_create_object(env_, &params);
            
            napi_value loadTypeValue;
            const char* loadTypeStr = (loadType == LoadType::REFRESH) ? "refresh" : 
                                     (loadType == LoadType::PREPEND) ? "prepend" : "append";
            napi_create_string_utf8(env_, loadTypeStr, NAPI_AUTO_LENGTH, &loadTypeValue);
            napi_set_named_property(env_, params, "loadType", loadTypeValue);
            
            napi_value keyValue;
            napi_create_int32(env_, (loadType == LoadType::REFRESH) ? 0 : currentKey_, &keyValue);
            napi_set_named_property(env_, params, "key", keyValue);
            
            napi_value loadSizeValue;
            int loadSize = (loadType == LoadType::REFRESH) ? config_.initialLoadSize : config_.pageSize;
            napi_create_int32(env_, loadSize, &loadSizeValue);
            napi_set_named_property(env_, params, "loadSize", loadSizeValue);
            
            // Call load method
            napi_value loadMethod;
            napi_get_named_property(env_, sourceObj, "load", &loadMethod);
            
            napi_value args[1] = {params};
            napi_value result;
            napi_status status = napi_call_function(env_, sourceObj, loadMethod, 1, args, &result);
            
            if (status == napi_ok) {
                processLoadResult(result, loadType);
            } else {
                handleLoadError("Failed to call load method");
            }
            
            napi_close_handle_scope(env_, scope);
            isLoading_ = false;
        }).detach();
    }
    
    // Process load result
    void processLoadResult(napi_value result, LoadType loadType) {
        // Get data array
        napi_value dataArray;
        napi_get_named_property(env_, result, "data", &dataArray);
        
        uint32_t length;
        napi_get_array_length(env_, dataArray, &length);
        
        std::vector<std::shared_ptr<PagingItem<std::string>>> newItems;
        newItems.reserve(length);
        
        for (uint32_t i = 0; i < length; i++) {
            napi_value element;
            napi_get_element(env_, dataArray, i, &element);
            
            auto item = std::make_shared<PagingItem<std::string>>();
            
            napi_value idValue;
            napi_get_named_property(env_, element, "id", &idValue);
            item->id = getString(env_, idValue);
            
            napi_value dataValue;
            napi_get_named_property(env_, element, "data", &dataValue);
            item->data = getString(env_, dataValue);
            
            newItems.push_back(item);
        }
        
        // Check for next key
        napi_value nextKey;
        if (napi_get_named_property(env_, result, "nextKey", &nextKey) == napi_ok) {
            napi_valuetype type;
            napi_typeof(env_, nextKey, &type);
            hasMoreData_ = (type != napi_undefined && type != napi_null);
            
            if (hasMoreData_) {
                napi_get_value_int32(env_, nextKey, &currentKey_);
            }
        }
        
        // Update cached items
        {
            std::lock_guard<std::mutex> lock(cacheMutex_);
            if (loadType == LoadType::REFRESH) {
                cachedItems_ = std::move(newItems);
            } else if (loadType == LoadType::APPEND) {
                cachedItems_.insert(cachedItems_.end(), 
                                  std::make_move_iterator(newItems.begin()),
                                  std::make_move_iterator(newItems.end()));
            } else if (loadType == LoadType::PREPEND) {
                cachedItems_.insert(cachedItems_.begin(), 
                                  std::make_move_iterator(newItems.begin()),
                                  std::make_move_iterator(newItems.end()));
            }
            
            // Trim if needed
            if (cachedItems_.size() > static_cast<size_t>(config_.maxSize)) {
                if (loadType == LoadType::PREPEND) {
                    cachedItems_.resize(config_.maxSize);
                } else {
                    cachedItems_.erase(cachedItems_.begin(), 
                                     cachedItems_.begin() + (cachedItems_.size() - config_.maxSize));
                }
            }
        }
        
        // Create load states
        CombinedLoadStates loadStates;
        if (loadType == LoadType::REFRESH) {
            loadStates.refresh.isLoading = false;
        } else if (loadType == LoadType::APPEND) {
            loadStates.append.isLoading = false;
        } else if (loadType == LoadType::PREPEND) {
            loadStates.prepend.isLoading = false;
        }
        
        // Submit to controller
        PagingData<std::string> pagingData(cachedItems_, loadStates);
        controller_->submitData(pagingData);
        
        LOGI("Processed load result: %zu new items, total %zu items", 
             newItems.size(), cachedItems_.size());
    }
    
    // Handle load error
    void handleLoadError(const std::string& errorMsg) {
        CombinedLoadStates loadStates;
        loadStates.refresh.isError = true;
        loadStates.refresh.errorMessage = errorMsg;
        
        notifyLoadStateChange(loadStates);
        LOGE("Load error: %s", errorMsg.c_str());
    }
    
    // Notify load state change
    void notifyLoadStateChange(const CombinedLoadStates& states) {
        if (!loadStateListenerRef_ || !env_) return;
        
        executeOnMainThread([this, states]() {
            napi_handle_scope scope;
            napi_open_handle_scope(env_, &scope);
            
            napi_value callback;
            napi_get_reference_value(env_, loadStateListenerRef_, &callback);
            
            napi_value statesObj = createLoadStatesObject(env_, states);
            
            napi_value args[1] = {statesObj};
            napi_value result;
            napi_call_function(env_, nullptr, callback, 1, args, &result);
            
            napi_close_handle_scope(env_, scope);
        });
    }
    
    // Notify pages updated
    void notifyPagesUpdated() {
        if (!onPagesUpdatedListenerRef_ || !env_) return;
        
        executeOnMainThread([this]() {
            napi_handle_scope scope;
            napi_open_handle_scope(env_, &scope);
            
            napi_value callback;
            napi_get_reference_value(env_, onPagesUpdatedListenerRef_, &callback);
            
            napi_value result;
            napi_call_function(env_, nullptr, callback, 0, nullptr, &result);
            
            napi_close_handle_scope(env_, scope);
        });
    }
    
    // Helper: Create load states object
    napi_value createLoadStatesObject(napi_env env, const CombinedLoadStates& states) {
        napi_value statesObj;
        napi_create_object(env, &statesObj);
        
        auto createLoadState = [env](const LoadState& state) -> napi_value {
            napi_value obj;
            napi_create_object(env, &obj);
            
            napi_value isLoading;
            napi_get_boolean(env, state.isLoading, &isLoading);
            napi_set_named_property(env, obj, "isLoading", isLoading);
            
            napi_value isError;
            napi_get_boolean(env, state.isError, &isError);
            napi_set_named_property(env, obj, "isError", isError);
            
            if (!state.errorMessage.empty()) {
                napi_value errorMsg;
                napi_create_string_utf8(env, state.errorMessage.c_str(), 
                                      state.errorMessage.length(), &errorMsg);
                napi_set_named_property(env, obj, "errorMessage", errorMsg);
            }
            
            return obj;
        };
        
        napi_set_named_property(env, statesObj, "refresh", createLoadState(states.refresh));
        napi_set_named_property(env, statesObj, "prepend", createLoadState(states.prepend));
        napi_set_named_property(env, statesObj, "append", createLoadState(states.append));
        
        return statesObj;
    }
    
    // Helper: Call JS callback
    void callJSCallback(napi_ref callbackRef, int arg1, int arg2) {
        napi_handle_scope scope;
        napi_open_handle_scope(env_, &scope);
        
        napi_value callback;
        napi_get_reference_value(env_, callbackRef, &callback);
        
        napi_value args[2];
        napi_create_int32(env_, arg1, &args[0]);
        napi_create_int32(env_, arg2, &args[1]);
        
        napi_value result;
        napi_call_function(env_, nullptr, callback, 2, args, &result);
        
        napi_close_handle_scope(env_, scope);
    }
    
    // Helper: Get string from napi_value
    static std::string getString(napi_env env, napi_value value) {
        size_t length;
        napi_get_value_string_utf8(env, value, nullptr, 0, &length);
        std::string str(length, '\0');
        napi_get_value_string_utf8(env, value, &str[0], length + 1, &length);
        return str;
    }
    
    // Helper: Set property
    static void setProperty(napi_env env, napi_value obj, const char* key, const std::string& value) {
        napi_value napiValue;
        napi_create_string_utf8(env, value.c_str(), value.length(), &napiValue);
        napi_set_named_property(env, obj, key, napiValue);
    }
    
    // Cleanup references
    void cleanupRefs() {
        if (env_) {
            if (itemBuilderRef_) napi_delete_reference(env_, itemBuilderRef_);
            if (pagingSourceRef_) napi_delete_reference(env_, pagingSourceRef_);
            if (loadStateListenerRef_) napi_delete_reference(env_, loadStateListenerRef_);
            if (onPagesUpdatedListenerRef_) napi_delete_reference(env_, onPagesUpdatedListenerRef_);
            if (onInsertedRef_) napi_delete_reference(env_, onInsertedRef_);
            if (onRemovedRef_) napi_delete_reference(env_, onRemovedRef_);
            if (onMovedRef_) napi_delete_reference(env_, onMovedRef_);
            if (onChangedRef_) napi_delete_reference(env_, onChangedRef_);
        }
    }
};

// ============ NAPI Export Functions ============

static napi_value CreateEnhancedPagingController(napi_env env, napi_callback_info info) {
    auto* controller = new EnhancedPagingControllerNAPI();
    
    napi_value result;
    napi_create_external(env, controller, 
        [](napi_env env, void* data, void* hint) {
            delete static_cast<EnhancedPagingControllerNAPI*>(data);
        }, nullptr, &result);
    
    return result;
}

static napi_value SetPagingSource(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->SetPagingSource(env, args[1]);
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value SubmitData(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->SubmitData(env, args[1]);
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value Refresh(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->Refresh();
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value Retry(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->Retry();
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value GetItem(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    
    int32_t position;
    napi_get_value_int32(env, args[1], &position);
    
    return controller->GetItem(env, position);
}

static napi_value Peek(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    
    int32_t index;
    napi_get_value_int32(env, args[1], &index);
    
    return controller->Peek(env, index);
}

static napi_value GetSnapshot(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    
    return controller->GetSnapshot(env);
}

static napi_value GetItemCount(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    
    napi_value result;
    napi_create_int32(env, static_cast<int32_t>(controller->GetItemCount()), &result);
    return result;
}

static napi_value GetLoadStates(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    
    return controller->GetLoadStates(env);
}

static napi_value SetUpdateCallbacks(napi_env env, napi_callback_info info) {
    size_t argc = 5;
    napi_value args[5];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    
    controller->SetUpdateCallbacks(env, 
        argc > 1 ? args[1] : nullptr,  // onInserted
        argc > 2 ? args[2] : nullptr,  // onRemoved
        argc > 3 ? args[3] : nullptr,  // onMoved
        argc > 4 ? args[4] : nullptr); // onChanged
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value SetLoadStateListener(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->SetLoadStateListener(env, args[1]);
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value SetOnPagesUpdatedListener(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->SetOnPagesUpdatedListener(env, args[1]);
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value SetItemBuilder(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->SetItemBuilder(env, args[1]);
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

static napi_value GetNode(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    
    napi_value result;
    napi_create_external(env, controller->GetNode(), nullptr, nullptr, &result);
    return result;
}

static napi_value SetConfig(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    EnhancedPagingControllerNAPI* controller;
    napi_get_value_external(env, args[0], reinterpret_cast<void**>(&controller));
    controller->SetConfig(env, args[1]);
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    return undefined;
}

// ============ Module Initialization ============

EXTERN_C_START
static napi_value InitEnhancedPaging(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"createEnhancedPagingController", nullptr, CreateEnhancedPagingController, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setPagingSource", nullptr, SetPagingSource, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"submitData", nullptr, SubmitData, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"refresh", nullptr, Refresh, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"retry", nullptr, Retry, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getItem", nullptr, GetItem, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"peek", nullptr, Peek, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getSnapshot", nullptr, GetSnapshot, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getItemCount", nullptr, GetItemCount, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getLoadStates", nullptr, GetLoadStates, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setUpdateCallbacks", nullptr, SetUpdateCallbacks, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setLoadStateListener", nullptr, SetLoadStateListener, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setOnPagesUpdatedListener", nullptr, SetOnPagesUpdatedListener, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setItemBuilder", nullptr, SetItemBuilder, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getNode", nullptr, GetNode, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setConfig", nullptr, SetConfig, 
         nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    
    LOGI("Enhanced Paging module initialized");
    return exports;
}
EXTERN_C_END

static napi_module enhancedPagingModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = InitEnhancedPaging,
    .nm_modname = "enhancedPaging",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEnhancedPagingModule(void) {
    napi_module_register(&enhancedPagingModule);
}